home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / smaltalk.lha / smalltalk-1.1.1 / msttree.c < prev    next >
C/C++ Source or Header  |  1991-09-12  |  18KB  |  791 lines

  1. /***********************************************************************
  2.  *
  3.  *    Semantic Tree manipulation module.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbyrne    30 Dec 88      Created.
  36.  *
  37.  */
  38.  
  39.  
  40. #include "mst.h"
  41. #include "mstsym.h"
  42. #include "msttree.h"
  43. #include <stdio.h>
  44.  
  45. char    *nilName = "(nil)"; /* how to print nil */
  46.  
  47. Boolean hadError = false;
  48.  
  49. static TreeNode makeMethodNode(), makeListNode(), makeExprNode();
  50. static TreeNode makeTreeNode();
  51. static OOP    makeUnarySelector(), makeBinarySelector();
  52. static void    freeNode(), freeMethodNode(), freeExprNode(), freeListNode(),
  53.           freeConstNode();
  54. static void    printMethodNode(), printExprNode(), printListNode(),
  55.           printConstNode(), printNodeType(), indent(), printSelector();
  56.  
  57. static OOP    *binopSymbols[] = { /* indexed by binop */
  58.   &nilSymbol,            /* there is no zeroth entry  */
  59.   &plusSymbol,
  60.   &minusSymbol,
  61.   ×Symbol,
  62.   ÷Symbol,
  63.   &lessThanSymbol,
  64.   &greaterThanSymbol,
  65.   &equalSymbol,
  66.   ¬EqualSymbol,
  67.   &lessEqualSymbol,
  68.   &greaterEqualSymbol,
  69.   &integerDivideSymbol,
  70.   &remainderSymbol,
  71.   &sameObjectSymbol,
  72.   ¬SameObjectSymbol,
  73.   &orSymbol,
  74.   &andSymbol
  75. };
  76.  
  77. /* Used only for printing tree node names when debugging */
  78. static char *nodeTypeNames[] = {
  79.   "methodNodeType",         /* methodNodeType */
  80.   "unaryExprType",         /* unaryExprType */
  81.   "binaryExprType",         /* binaryExprType */
  82.   "keywordExprType",         /* keywordExprType */
  83.   "variableNodeType",         /* variableNodeType */
  84.   "keywordListType",         /* keywordListType */
  85.   "variableListType",         /* variableListType */
  86.   "statementListType",         /* statementListType */
  87.   "returnExprType",         /* returnExprType */
  88.   "assignExprType",         /* assignExprType */
  89.   "constExprType",         /* constExprType */
  90.   "symbolNodeType",         /* symbolNodeType */
  91.   "arrayEltListType",         /* arrayEltListType */
  92.   "blockNodeType",         /* blockNodeType */
  93.   "cascadedMessageNodeType",     /* cascadedMessageNodeType */
  94.   "messageListType"         /* messageListType */
  95. };
  96.  
  97.  
  98.  
  99. /*
  100.  *    TreeNode makeArrayElt(elt)
  101.  *
  102.  * Description
  103.  *
  104.  *    Create an element of an array constant, which is a list type object.
  105.  *    Return the element with the next field NILed out.
  106.  *
  107.  * Inputs
  108.  *
  109.  *    elt   : TreeNode array element to use
  110.  *
  111.  * Outputs
  112.  *
  113.  *    TreeNode of type arrayEltListType that contains "elt".
  114.  */
  115. TreeNode makeArrayElt(elt)
  116. TreeNode elt;
  117. {
  118.   return (makeListNode(arrayEltListType, nil, elt));
  119. }
  120.  
  121.   
  122. /*
  123.  *    TreeNode makeMethod(selectorExpr, temporaries, primitiveIndex,
  124.  *                statements)
  125.  *
  126.  * Description
  127.  *
  128.  *    Create a method node.  The method will be invoked by a selector dervied
  129.  *    from "selectorExpr", it has (possibly nil) "temporaries" variables,
  130.  *    and contains "statements".  If the method has a primitive associated
  131.  *    with it, then "primitiveIndex" is non-zero.
  132.  *
  133.  * Inputs
  134.  *
  135.  *    selectorExpr: 
  136.  *        Expression that's to be the selector for this method.
  137.  *    temporaries: 
  138.  *        Possibly nil list of temporary variable names.
  139.  *    primitiveIndex:
  140.  *        Integer.  If non-zero, this method has associated with it
  141.  *        a primitive with index "primitiveIndex".
  142.  *    statements: 
  143.  *        List of statements that comprise the procedural part of this
  144.  *        method.
  145.  *
  146.  * Outputs
  147.  *
  148.  *    TreeNode of type methodNodeType.
  149.  */
  150. TreeNode makeMethod(selectorExpr, temporaries, primitiveIndex, statements)
  151. TreeNode selectorExpr, temporaries, statements;
  152. int    primitiveIndex;
  153. {
  154.   return (makeMethodNode(methodNodeType, selectorExpr,
  155.              temporaries, primitiveIndex, statements));
  156. }
  157.  
  158.  
  159. /*
  160.  *    TreeNode makeCascadedMessage(messageExpr, cascadedMessages)
  161.  *
  162.  * Description
  163.  *
  164.  *    Creates a node for holding a list of cascaded messages (basically an
  165.  *    Expr node that isn't using its symbol.  "messageExpr" is the expression
  166.  *    invoke first as it computes the receiver.  Then the remaining cascaded
  167.  *    messages are sent to that receiver.
  168.  *
  169.  * Inputs
  170.  *
  171.  *    messageExpr: 
  172.  *        Evaluates to the receiver of the cascaded messages
  173.  *    cascadedMessages: 
  174.  *        List of the cascaded messages to send to the receiver.
  175.  *
  176.  * Outputs
  177.  *
  178.  *    TreeNode of type cascadedMessageTypeNode.
  179.  */
  180. TreeNode makeCascadedMessage(messageExpr, cascadedMessages)
  181. TreeNode messageExpr, cascadedMessages;
  182. {
  183.   return (makeExprNode(cascadedMessageNodeType, messageExpr, nil,
  184.                cascadedMessages));
  185. }
  186.  
  187.  
  188. TreeNode makeUnaryExpr(receiver, unarySelectorExpr)
  189. TreeNode receiver;
  190. char     *unarySelectorExpr;
  191. {
  192.   OOP        selector;
  193.  
  194.   selector = makeUnarySelector(unarySelectorExpr);
  195.   return (makeExprNode(unaryExprType, receiver, selector, nil));
  196. }
  197.  
  198. TreeNode internBinOP(binaryOp)
  199. char    *binaryOp;
  200. {
  201.   return (makeExprNode(symbolNodeType, nil, makeBinarySelector(binaryOp),
  202.                nil));
  203. }
  204.  
  205. TreeNode internIdent(ident)
  206. char    *ident;
  207. {
  208.   return (makeExprNode(symbolNodeType, nil, internString(ident), nil));
  209. }
  210.  
  211. TreeNode makeStatementList(expression, statements)
  212. TreeNode expression, statements;
  213. {
  214.   return (makeExprNode(statementListType, expression, nilOOP, statements));
  215. }
  216.  
  217. TreeNode makeReturn(expression)
  218. TreeNode expression;
  219. {
  220.   return (makeExprNode(returnExprType, expression, nilOOP, nil));
  221. }
  222.  
  223. TreeNode makeKeywordExpr(receiver, keywordMessage)
  224. TreeNode receiver, keywordMessage;
  225. {
  226.   return (makeExprNode(keywordExprType, receiver, nilOOP, keywordMessage));
  227. }
  228.  
  229. TreeNode makeAssign(variables, expression)
  230. TreeNode variables, expression;
  231. {
  232.   return (makeExprNode(assignExprType, variables, nilOOP, expression));
  233. }
  234.  
  235. TreeNode makeKeywordList(keyword, expression)
  236. char    *keyword;
  237. TreeNode expression;
  238. {
  239.   return (makeListNode(keywordListType, keyword, expression));
  240. }
  241.  
  242. /*
  243.  *    TreeNode makeVariableList(variable)
  244.  *
  245.  * Description
  246.  *
  247.  *    Given a variable tree node, this routine returns a variable list tree
  248.  *    node with a nil next link.  Actually, we rely on the fact that a
  249.  *    variable is represented as a tree node of type ListNode, so  all we do
  250.  *    is change the node tag to variableListType.
  251.  *
  252.  * Inputs
  253.  *
  254.  *    variable: 
  255.  *        Name of variable that's to be part of the list, TreeNode.
  256.  *
  257.  * Outputs
  258.  *
  259.  *    New TreeNode.
  260.  */
  261. TreeNode makeVariableList(variable)
  262. TreeNode variable;
  263. {
  264.   variable->nodeType = variableListType;
  265.   return (variable);
  266. }
  267.  
  268.  
  269. TreeNode makeBinaryExpr(receiver, binaryOp, argument)
  270. TreeNode receiver, argument;
  271. char    *binaryOp;
  272. {
  273.   OOP        selector;
  274.  
  275.   selector = makeBinarySelector(binaryOp);
  276.   return (makeExprNode(binaryExprType, receiver, selector, argument));
  277. }
  278.  
  279. TreeNode makeMessageList(messageElt)
  280. TreeNode messageElt;
  281. {
  282.   return (makeListNode(messageListType, nil, messageElt));
  283. }
  284.  
  285. /*
  286.  *    TreeNode makeBlock(temporaries, statements)
  287.  *
  288.  * Description
  289.  *
  290.  *    Creates a block tree node and returns it.
  291.  *
  292.  * Inputs
  293.  *
  294.  *    temporaries: 
  295.  *        Possibly nil list of temporary variable names to use for this
  296.  *        block 
  297.  *    statements: 
  298.  *        List of statements that are the procedure part of this block.
  299.  *
  300.  * Outputs
  301.  *
  302.  *    New tree node.
  303.  */
  304. TreeNode makeBlock(temporaries, statements)
  305. TreeNode temporaries, statements;
  306. {
  307.   return (makeMethodNode(blockNodeType, nil, temporaries, 0, statements));
  308. }
  309.  
  310. TreeNode makeVariable(name)
  311. char    *name;
  312. {
  313.   return (makeListNode(variableNodeType, name, nil));
  314. }
  315.  
  316.  
  317. TreeNode makeIntConstant(ival)
  318. long    ival;
  319. {
  320.   TreeNode     result;
  321.  
  322.   result = makeTreeNode(constExprType);
  323.   result->vConst.constType = intConst;
  324.   result->vConst.val.iVal = ival;
  325.  
  326.   return (result);
  327. }
  328.  
  329. TreeNode makeFloatConstant(fval)
  330. double    fval;
  331. {
  332.   TreeNode     result;
  333.  
  334.   result = makeTreeNode(constExprType);
  335.   result->vConst.constType = floatConst;
  336.   result->vConst.val.fVal = fval;
  337.  
  338.   return (result);
  339. }
  340.  
  341. TreeNode makeCharConstant(cval)
  342. char    cval;
  343. {
  344.   TreeNode     result;
  345.  
  346.   result = makeTreeNode(constExprType);
  347.   result->vConst.constType = charConst;
  348.   result->vConst.val.cVal = cval;
  349.  
  350.   return (result);
  351. }
  352.  
  353. TreeNode makeStringConstant(sval)
  354. char    *sval;
  355. {
  356.   TreeNode     result;
  357.  
  358.   result = makeTreeNode(constExprType);
  359.   result->vConst.constType = stringConst;
  360.   result->vConst.val.sVal = sval;
  361.  
  362.   return (result);
  363. }
  364.  
  365. TreeNode makeSymbolConstant(symbolNode)
  366. TreeNode symbolNode;
  367. {
  368.   TreeNode     result;
  369.  
  370.   result = makeTreeNode(constExprType);
  371.   result->vConst.constType = symbolConst;
  372.   if (symbolNode) {
  373.     result->vConst.val.symVal = symbolNode->vExpr.selector;
  374.     freeNode(symbolNode);
  375.   } else {
  376.     result->vConst.val.symVal = nilOOP;
  377.   }
  378.  
  379.   return (result);
  380. }
  381.  
  382. TreeNode makeArrayConstant(aval)
  383. TreeNode aval;
  384. {
  385.   TreeNode     result;
  386.  
  387.   result = makeTreeNode(constExprType);
  388.   result->vConst.constType = arrayConst;
  389.   result->vConst.val.aVal = aval;
  390.  
  391.   return (result);
  392. }
  393.  
  394.  
  395. /*
  396.  *    void addNode(n1, n2)
  397.  *
  398.  * Description
  399.  *
  400.  *    adds node "n2" onto a list of nodes headed by "n1".  "n1" contains
  401.  *    the address of the last "next" field in the chain, so storing "n2" into
  402.  *    there indirectly and then making that "next" field point to "n2"'s
  403.  *    "next" field works properly.
  404.  *
  405.  * Inputs
  406.  *
  407.  *    n1    : head of list of nodes, of type listNode.
  408.  *    n2    : node to be added, of type listNode.
  409.  *
  410.  */
  411. void addNode(n1, n2)
  412. TreeNode n1, n2;
  413. {
  414.   *(n1->vList.nextAddr) = n2;
  415.   n1->vList.nextAddr = n2->vList.nextAddr; /* since they're all created this
  416.                         * way anyway, we might as well
  417.                         * use it to our advantage */
  418. }
  419.  
  420. void freeTree(tree)
  421. TreeNode tree;
  422. {
  423.   if (tree == nil) {
  424.     return;
  425.   }
  426.  
  427.   switch (tree->nodeType) {
  428.   case methodNodeType:
  429.   case blockNodeType:
  430.     freeMethodNode(tree);
  431.     break;
  432.     
  433.   case symbolNodeType:
  434.   case unaryExprType:
  435.   case binaryExprType:
  436.   case keywordExprType:
  437.   case cascadedMessageNodeType:
  438.   case statementListType:
  439.   case returnExprType:
  440.   case assignExprType:
  441.     freeExprNode(tree);
  442.     break;
  443.     
  444.   case variableNodeType:
  445.   case keywordListType:
  446.   case variableListType:
  447.   case arrayEltListType:
  448.   case messageListType:
  449.     freeListNode(tree);
  450.     break;
  451.  
  452.   case constExprType:
  453.     freeConstNode(tree);
  454.     break;
  455.  
  456.   }
  457. }
  458.  
  459.  
  460.  
  461. /***********************************************************************
  462.  *
  463.  * Internal tree construction routines.
  464.  *
  465.  ***********************************************************************/
  466.  
  467.  
  468. static TreeNode makeMethodNode(nodeType, selectorExpr, temporaries,
  469.                    primitiveIndex, statements)
  470. NodeType nodeType;
  471. TreeNode selectorExpr, temporaries, statements;
  472. int    primitiveIndex;
  473. {
  474.   TreeNode    result;
  475.  
  476.   result = makeTreeNode(nodeType);
  477.   result->vMethod.selectorExpr = selectorExpr;
  478.   result->vMethod.temporaries = temporaries;
  479.   result->vMethod.primitiveIndex = primitiveIndex;
  480.   result->vMethod.statements = statements;
  481.   return (result);
  482. }
  483.  
  484. static TreeNode makeListNode(nodeType, name, value)
  485. NodeType nodeType;
  486. char    *name;
  487. TreeNode value;
  488. {
  489.   TreeNode result;
  490.  
  491.   result = makeTreeNode(nodeType);
  492.   result->vList.name = name;
  493.   result->vList.value = value;
  494.   result->vList.next = nil;
  495.   result->vList.nextAddr = &result->vList.next;
  496.   return (result);
  497. }
  498.  
  499. static TreeNode makeExprNode(nodeType, receiver, selector, expression)
  500. NodeType nodeType;
  501. TreeNode receiver, expression;
  502. OOP    selector;
  503. {
  504.   TreeNode result;
  505.  
  506.   result = makeTreeNode(nodeType);
  507.   result->vExpr.receiver = receiver;
  508.   result->vExpr.selector = selector;
  509.   result->vExpr.expression = expression;
  510.   return (result);
  511. }
  512.  
  513. static TreeNode makeTreeNode(nodeType)
  514. NodeType nodeType;
  515. {
  516.   TreeNode result;
  517.  
  518.   result = (TreeNode)malloc(sizeof(struct TreeNodeStruct));
  519.   result->nodeType = nodeType;
  520.   return (result);
  521. }
  522.  
  523. /* ### these should probably be moved over into the symbol table module, yes?*/
  524.  
  525. static OOP makeUnarySelector(name)
  526. char    *name;
  527. {
  528.   return (internString(name));
  529. }
  530.  
  531. static OOP makeBinarySelector(binaryOp)
  532. char    *binaryOp;
  533. {
  534.   return (internString(binaryOp));
  535. }
  536.  
  537. /***********************************************************************
  538.  *
  539.  * Internal tree destruction routines.
  540.  *
  541.  ***********************************************************************/
  542.  
  543. static void freeMethodNode(node)
  544. TreeNode node;
  545. {
  546.   freeTree(node->vMethod.selectorExpr);
  547.   freeTree(node->vMethod.temporaries);
  548.   freeTree(node->vMethod.statements);
  549.   freeNode(node);
  550. }
  551.  
  552. static void freeExprNode(node)
  553. TreeNode node;
  554. {
  555.   freeTree(node->vExpr.receiver);
  556.   freeTree(node->vExpr.expression);
  557.   freeNode(node);
  558. }
  559.  
  560. static void freeListNode(node)
  561. TreeNode node;
  562. {
  563.   freeTree(node->vList.value);
  564.   freeTree(node->vList.next);
  565.   if (node->vList.name) {
  566.     free(node->vList.name);
  567.   }
  568.  
  569.   freeNode(node);
  570. }
  571.  
  572. static void freeConstNode(node)
  573. TreeNode node;
  574. {
  575.   switch (node->vConst.constType) {
  576.   case intConst:
  577.   case floatConst:
  578.   case charConst:
  579.   case symbolConst:
  580.     /* these have no storage of their own */
  581.     break;
  582.  
  583.   case stringConst:
  584.     if (node->vConst.val.sVal) {
  585.       free(node->vConst.val.sVal);
  586.     } else {
  587.       errorf("Internal error: badly formed tree for string constant"); 
  588.     }
  589.     break;
  590.  
  591.   case arrayConst:
  592.     freeTree(node->vConst.val.aVal);
  593.     break;
  594.  
  595.   default:
  596.     errorf("Internal error: corrupted tree structure"); 
  597.   }
  598.  
  599.   freeNode(node);
  600. }
  601.  
  602.  
  603. static void freeNode(node)
  604. TreeNode node;
  605. {
  606.   free(node);
  607. }
  608.  
  609.  
  610. /***********************************************************************
  611.  *
  612.  *    Printing routines.
  613.  *
  614.  ***********************************************************************/
  615.  
  616.  
  617. void printTree(node, level)
  618. TreeNode node;
  619. int level;
  620. {
  621.   if (node == nil) {
  622.     indent(level);
  623.     printf("%s\n", nilName);
  624.     return;
  625.   }
  626.  
  627.   switch (node->nodeType) {
  628.   case methodNodeType:
  629.   case blockNodeType:
  630.     printMethodNode(node, level);
  631.     break;
  632.     
  633.   case symbolNodeType:
  634.   case unaryExprType:
  635.   case binaryExprType:
  636.   case keywordExprType:
  637.   case cascadedMessageNodeType:
  638.   case statementListType:
  639.   case returnExprType:
  640.   case assignExprType:
  641.     printExprNode(node, level);
  642.     break;
  643.     
  644.   case variableNodeType:
  645.   case keywordListType:
  646.   case variableListType:
  647.   case arrayEltListType:
  648.   case messageListType:
  649.     printListNode(node, level);
  650.     break;
  651.  
  652.   case constExprType:
  653.     printConstNode(node, level);
  654.     break;
  655.  
  656.   default:
  657.     errorf("Unknown tree note type %d\n", node->nodeType);
  658.   }
  659. }
  660.  
  661.  
  662. static void printListNode(node, level)
  663. TreeNode node;
  664. int level;
  665. {
  666.   printNodeType(node, level);
  667.   indent(level+1);
  668.   printf("name: %s\n", node->vList.name ? node->vList.name : nilName);
  669.   indent(level+1);
  670.   printf("value:\n");
  671.   printTree(node->vList.value, level+2);
  672.   indent(level+1);
  673.   printf("next:\n");
  674.   printTree(node->vList.next, level);
  675. }
  676.  
  677. static void printExprNode(node, level)
  678. TreeNode node;
  679. int level;
  680. {
  681.   printNodeType(node, level);
  682.   indent(level+1);
  683.   printf("selector: ");
  684.   if (!isNil(node->vExpr.selector)) {
  685.     printSelector(node->vExpr.selector);
  686.   } else {
  687.     printf("%s", nilName);
  688.   }
  689.   printf("\n");
  690.     
  691.   indent(level+1);
  692.   printf("receiver:\n");
  693.   printTree(node->vExpr.receiver, level+2);
  694.   /* ??? don't print the expression for unary type things, and don't print
  695.      the receiver for symbol nodes */
  696.   indent(level+1);
  697.   printf("expression:\n");
  698.   printTree(node->vExpr.expression, level+2);
  699. }
  700.  
  701. static void printMethodNode(node, level)
  702. TreeNode node;
  703. int level;
  704. {
  705.   printNodeType(node, level);
  706.   indent(level+1);
  707.   printf("selectorExpr: ");
  708.   printTree(node->vMethod.selectorExpr, level+2);
  709.   indent(level+1);
  710.   /* ??? don't print the temporaries label if there are no temporaries */
  711.   printf("temporaries:\n");
  712.   printTree(node->vMethod.temporaries, level+2);
  713.   indent(level+1);
  714.   printf("statements:\n");
  715.   printTree(node->vMethod.statements, level+2);
  716. }
  717.  
  718. static void printConstNode(node, level)
  719. TreeNode node;
  720. int level;
  721. {
  722.   indent(level);
  723.   switch (node->vConst.constType) {
  724.   case intConst:
  725.     printf("int: %ld\n", node->vConst.val.iVal);
  726.     break;
  727.  
  728.   case floatConst:
  729.     printf("float: %g\n", node->vConst.val.fVal);
  730.     break;
  731.  
  732.   case charConst:
  733.     printf("char: %c\n", node->vConst.val.cVal);
  734.     break;
  735.  
  736.   case stringConst:
  737.     printf("string: \"%s\"\n", node->vConst.val.sVal);
  738.     break;
  739.  
  740.   case symbolConst:
  741.     printf("symbol: ");
  742.     printSymbol(node->vConst.val.symVal);
  743.     printf("\n");
  744.     break;
  745.  
  746.   case arrayConst:
  747.     printf("array:\n");
  748.     printTree(node->vConst.val.aVal, level+1);
  749.     break;
  750.     
  751.   default:
  752.     errorf("Unknown constant type %d", node->vConst.constType);
  753.   }
  754. }
  755.  
  756.  
  757. static void printNodeType(node, level)
  758. TreeNode node;
  759. int level;
  760. {
  761.   indent(level);
  762.   printf("%s\n", nodeTypeNames[ENUM_INT(node->nodeType)]);
  763. }
  764.  
  765. /*
  766.  *    static void indent(level)
  767.  *
  768.  * Description
  769.  *
  770.  *    Indent the output by level*2 spaces.
  771.  *
  772.  * Inputs
  773.  *
  774.  *    level : Indentation level.  C integer.
  775.  *
  776.  */
  777. static void indent(level)
  778. int level;
  779. {
  780.   for (; level > 0; level--) {
  781.     printf("  ");
  782.   }
  783. }
  784.  
  785. static void printSelector(selector)
  786. OOP    selector;
  787. {
  788.   printSymbol(selector);
  789. }
  790.  
  791.